// Ακολουθεί μέθοδος με την οποία στήνεται ένα σκηνικό, ή καλύτερα ΤΟ σκηνικό στον
// skiser. Η μέθοδος αποτελεί ουσιαστικά το σημείο εκκίνησης της διαδικασίας, καθώς
// υπάρχει πληθώρα επιμέρους διαδικασιών που καλούνται αλυσιδωτά προκειμένου να
// στηεθεί το σκηνικό. Περιττό να πούμε ότι το στήσιμο του σκηνικού στον skiser
// γίνεται με βάση τα στοιχεία που υπάρχουν στην database.  

Skiniko.prototype.stisimo = function() {
	Log.fasi.nea('Στήσιμο σκηνικού');
	Log.print('Τραπέζια');
	this.stisimoTrapezi(DB.connection());
	return this;
};

// Διαβάζουμε τα ενεργά τραπέζια από την database και τα εντάσσουμε στο σκηνικό.

Skiniko.prototype.stisimoTrapezi = function(conn) {
	var
	skiniko = this,
	query = 'SELECT ' + Trapezi.projection + ' FROM `trapezi` WHERE `arxio` IS NULL ORDER BY `kodikos`';

	this.sitkep = {};
	this.izepart = {};

	conn.query(query, function(conn, rows) {
		Globals.awalk(rows, function(i, trapezi) {
			trapezi = new Trapezi(trapezi).trapeziPollSet();
			skiniko.skinikoTrapeziSet(trapezi);

			// Κρατάμε όλα τα ενεργά τραπέζια στη λίστα "izepart".

			skiniko.izepart[trapezi.kodikos] = null;

			// Κρατάμε όλους τους εμπλεκόμενους παίκτες στη λίστα "sitkep".

			trapezi.trapeziThesiWalk(function(thesi) {
				skiniko.sitkep[this.trapeziPektisGet(thesi)] = null;
			});
		});

		Log.print('Παράμετροι τραπεζιών');
		skiniko.izepart2 = {};
		skiniko.stisimoTrparam(conn);
	});

	return this;
};

// Διαβάζουμε τις παραμέτρους των ενεργών τραπεζιών και τις εντάσσουμε στο σκηνικό.

Skiniko.prototype.stisimoTrparam = function(conn) {
	var skiniko = this, kodikos, trapezi, query;

	for (kodikos in this.izepart) {
		trapezi = this.skinikoTrapeziGet(kodikos);
		skiniko.izepart2[kodikos] = null;
		delete skiniko.izepart[kodikos];

		query = 'SELECT ' + Trparam.projection + ' FROM `trparam` WHERE `trapezi` = ' + kodikos;
		conn.query(query, function(conn, rows) {
			Globals.awalk(rows, function(i, trparam) {
				trapezi.trapeziTrparamSet(new Trparam(trparam));
			});

			skiniko.stisimoTrparam(conn);
		});

		return this;
	}

	Log.print('Διανομές');
	delete this.izepart;
	this.imonaid = {};
	this.stisimoDianomi(conn);
	return this;
};

// Διαβάζουμε τις διανομές των ενεργών τραπεζιών και τις εντάσσουμε στο σκηνικό.

Skiniko.prototype.stisimoDianomi = function(conn) {
	var skiniko = this, kodikos, trapezi, query;

	for (kodikos in this.izepart2) {
		trapezi = this.skinikoTrapeziGet(kodikos);
		delete this.izepart2[kodikos];
		if (!trapezi) return this.stisimoDianomi(conn);

		query = 'SELECT ' + Dianomi.projection + ' FROM `dianomi` WHERE `trapezi` = ' +
			kodikos + ' ORDER BY `kodikos`';
		conn.query(query, function(conn, rows) {
			Globals.awalk(rows, function(i, dianomi) {
				trapezi.trapeziDianomiSet(dianomi = new Dianomi(dianomi));
				trapezi.dianomiArray.push(dianomi);
				telefteaDianomi = dianomi.dianomiKodikosGet();
			});

			// Κρατάμε την τελευταία διανομή κάθε ενεργού τραπεζιού.

			if (trapezi.trapeziIsDianomi())
			skiniko.imonaid[trapezi.trapeziTelefteaDianomi().dianomiKodikosGet()] = kodikos;

			// Συνεχίζουμε με τα υπόλοιπα τραπέζια.

			skiniko.stisimoDianomi(conn);
		});

		return this;
	}

	Log.print('Ενέργειες');
	delete this.izepart2;
	this.stisimoEnergia(conn);
	return this;
};

// Διαβάζουμε τις ενέργειες των τελευταίων διανομών των ενεργών τραπεζιών και
// τις εντάσσουμε στο σκηνικό.

Skiniko.prototype.stisimoEnergia = function(conn) {
	var skiniko = this, kodikos, trapezi, dianomi, query;

	for (kodikos in this.imonaid) {
		trapezi = this.skinikoTrapeziGet(this.imonaid[kodikos]);
		delete this.imonaid[kodikos];
		if (!trapezi) return this.stisimoEnergia(conn);

		dianomi = trapezi.trapeziDianomiGet(kodikos);
		if (!dianomi) this.stisimoEnergia(conn);

		query = 'SELECT ' + Energia.projection + ' FROM `energia` WHERE `dianomi` = ' +
			kodikos + ' ORDER BY `kodikos`';
		conn.query(query, function(conn, rows) {
			Globals.awalk(rows, function(i, energia) {
				dianomi.dianomiEnergiaSet(energia = new Energia(energia));
				dianomi.energiaArray.push(energia);
			});

			skiniko.stisimoEnergia(conn);
		});

		return this;
	}

	Log.print('Συζήτηση');
	delete this.imonaid;
	this.stisimoSizitisi(conn);
	return this;
};

// Διαβάζουμε όλες τις συζητήσεις που εξελλίσσονται τόσο στα διάφορα τραπέζια όσο
// και στο καφενείο.

Skiniko.prototype.stisimoSizitisi = function(conn) {
	var
	skiniko = this,
	query = 'SELECT ' + Sizitisi.projection + ' FROM `sizitisi` ORDER BY `kodikos`';

	conn.query(query, function(conn, rows) {
		Globals.awalk(rows, function(i, sizitisi) {
			var trapezi;

			// Στα πεδία του row συζήτησης υπάρχει και πεδίο τραπεζιού ως
			// αναφορά στον κωδικό τραπεζιού, ή null εφόσον πρόκειται για
			// τη συζήτηση του καφενείου. Κρατάμε την τιμή του πεδίου και
			// και το διαγράφουμε.

			trapezi = sizitisi.trapezi;
			delete sizitisi.trapezi;

			// Αν το πεδίο του τραπεζιού ήταν κενό, τότε πρόκειται για
			// τη συζήτηση του καφενείου.

			if (!trapezi) return skiniko.skinikoSizitisiSet(new Sizitisi(sizitisi));

			// Αλλιώς πρόκειται για τη συζήτηση του συγκεκριμένου τραπεζιού,
			// του οποίου όμως ελέγχουμε την ύπαρξη.

			trapezi = skiniko.skinikoTrapeziGet(trapezi);
			if (!trapezi) return console.error(sizitisi.kodikos + ': ορφανή συζήτηση');

			trapezi.trapeziSizitisiSet(new Sizitisi(sizitisi));
		});

		Log.print('Προσκλήσεις');
		skiniko.stisimoProsklisi(conn);
	});

	return this;
};

// Διαβάζουμε όλες τις προσκλήσεις και τις εντάσσουμε στο σκηνικό.

Skiniko.prototype.stisimoProsklisi = function(conn) {
	var
	skiniko = this,
	query = 'SELECT ' + Prosklisi.projection + ' FROM `prosklisi` ORDER BY `kodikos`';

	conn.query(query, function(conn, rows) {
		Globals.awalk(rows, function(i, prosklisi) {
			skiniko.skinikoProsklisiSet(new Prosklisi(prosklisi));
		});

		Log.print('Συνεδρίες');
		skiniko.stisimoSinedria(conn);
	});

	return this;
};

Skiniko.prototype.stisimoSinedria = function(conn) {
	var
	skiniko = this,
	query = 'SELECT ' + Sinedria.projection + ' FROM `sinedria` ORDER BY `isodos`';

	conn.query(query, function(conn, rows) {
		Globals.awalk(rows, function(i, sinedria) {
			var trapezi, thesi;

			// Μετατρέπουμε το database row της συνεδρίας σε αντικείμενο
			// συνεδρίας.

			sinedria = new Sinedria(sinedria);

			// Θέτουμε το poll στην τρέχουσα χρονική στιγμή.

			sinedria.
			sinedriaPollSet().
			feredataPollSet().
			feredataResetSet();

			// Ελέγχουμε και διορθώνουμε τα στοιχεία θέσης της συνεδρίας.

			trapezi = skiniko.skinikoTrapeziGet(sinedria.sinedriaTrapeziGet());
			if (trapezi) {
				thesi = trapezi.trapeziThesiPekti(sinedria.sinedriaPektisGet());
				if (thesi) {
					sinedria.thesi = thesi;
					sinedria.simetoxi = 'ΠΑΙΚΤΗΣ';
				}
				else {
					if (Prefadoros.oxiThesi(sinedria.thesi)) sinedria.thesi = 1;
					sinedria.simetoxi = 'ΘΕΑΤΗΣ';
				}
			}
			else {
				delete sinedria.trapezi;
				delete sinedria.thesi;
				delete sinedria.simetoxi;
			}

			// Εντάσσουμε τη συνεδρία στο σκηνικό.

			skiniko.skinikoSinedriaSet(sinedria);

			// Κρατάμε τον παίκτη στη λίστα "sitkep".

			skiniko.sitkep[sinedria.sinedriaPektisGet()] = null;
		});

		Log.print('Παίκτες');
		delete skiniko.sitkep[null];
		skiniko.sitkep2 = {};
		skiniko.stisimoPektis(conn);
	});

	return this;
};

Skiniko.prototype.stisimoPektis = function(conn) {
	var skiniko = this, login, query;

	for (login in this.sitkep) {
		delete this.sitkep[login];
		this.sitkep2[login] = null;
		query = 'SELECT ' + Pektis.projection + ' FROM `pektis` WHERE `login` = ' + login.json();
		conn.query(query, function(conn, rows) {
			Globals.awalk(rows, function(i, pektis) {
				pektis.poll = Globals.tora();
				skiniko.skinikoPektisSet(new Pektis(pektis));
			});

			skiniko.stisimoPektis(conn);
		});

		return this;
	}

	Log.print('Παράμετροι παικτών');
	this.stisimoPeparam(conn);
	return this;
};

Skiniko.prototype.stisimoPeparam = function(conn) {
	var skiniko = this, login, pektis, query;

	for (login in this.sitkep2) {
		delete skiniko.sitkep2[login];
		skiniko.sitkep[login] = null;
		pektis = this.skinikoPektisGet(login);
		if (!pektis) return this.stisimoPeparam(conn);

		query = 'SELECT ' + Peparam.projection + ' FROM `peparam` WHERE `pektis` = ' + login.json();
		conn.query(query, function(conn, rows) {
			Globals.awalk(rows, function(i, peparam) {
				pektis.pektisPeparamSet(new Peparam(peparam));
			});

			skiniko.stisimoPeparam(conn);
		});

		return this;
	}

	delete this.sitkep2;
	Log.print('Σχέσεις');
	this.stisimoSxesi(conn);
	return this;
};

Skiniko.prototype.stisimoSxesi = function(conn) {
	var skiniko = this, login, pektis, query;

	for (login in this.sitkep) {
		delete skiniko.sitkep[login];
		pektis = this.skinikoPektisGet(login);
		if (!pektis) return this.stisimoSxesi(conn);

		query = 'SELECT ' + Sxesi.projection + ' FROM `sxesi` WHERE `pektis` = ' + login.json();
		conn.query(query, function(conn, rows) {
			Globals.awalk(rows, function(i, sxesi) {
				pektis.pektisSxesiSet(sxesi['sxetizomenos'], sxesi['sxesi']);
			});

			skiniko.stisimoSxesi(conn);
		});

		return this;
	}

	delete this.sitkep;
	this.stisimoTelos(conn);
	return this;
};

Skiniko.prototype.stisimoTelos = function(conn) {
	conn.free();
	Log.print('Replay παρτίδων');
	this.skinikoTrapeziWalk(function() {
		this.partidaReplay();
	});
	this.kinisi = [];
	Peripolos.setup();
	Server.ekinisi(this);
	Log.fasi.nea('Node server is up and running');
	return this;
};

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Trapezi.prototype.trapeziKlidoma = function() {
	if (this.klidoma) return false;
	this.klidoma = Globals.torams();
	return this.klidoma;
};

Trapezi.xeklidomaMax = 0;

Trapezi.prototype.trapeziXeklidoma = function() {
	var dt;

	if (!this.hasOwnProperty('klidoma')) return this;

	dt = Globals.torams() - this.klidoma;
	delete this.klidoma;

	if (dt <= Trapezi.xeklidomaMax) return this;

	Trapezi.xeklidomaMax = dt;
	console.log('Trapezi.xeklidomaMax = ', dt + 'ms');
	return this;
};

Trapezi.prototype.trapeziKlidomaGet = function() {
	return this.klidoma;
};

Trapezi.prototype.trapeziIsKlidomeno = function() {
	return this.klidoma;
};

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Η μέθοδος "trapeziNeaDianomi" δημιουργεί νέα διανομή για το ανά χείρας
// τραπέζι. Ως παραμέτρους δέχεται μια database connection, μια callback
// function που θα κληθεί σε περίπτωση επιτυχίας και μια callback function
// που θα κληθεί σε περίπτωση αποτυχίας. Οι callback functions καλούνται ως
// μέθοδοι του τραπεζιού με τις εξής παραμέτρους:
//
// Επιτυχία: Σύνδεση, Κίνηση διανομής, Ενέργεια διανομής
//
// Αποτυχία: Database connection

Trapezi.prototype.trapeziNeaDianomi = function(conn, success, fail) {
	var trapezi = this, trapeziKodikos, telefteaDianomi, dealer, query;

	if (!fail) fail = function(conn) {
		conn.rollback();
		this.trapeziXeklidoma();
	};

	trapeziKodikos = this.trapeziKodikosGet();
	telefteaDianomi = this.trapeziTelefteaDianomi();
	dealer = telefteaDianomi ? telefteaDianomi.dianomiDealerGet().epomeniThesi() : 1;
	query = 'INSERT INTO `dianomi` (`trapezi`, `dealer`) VALUES (' + trapeziKodikos + ', ' + dealer + ')';
	conn.connection.query(query, function(err, res) {
		if (err || (res.affectedRows != 1)) {
			console.error('αποτυχία εισαγωγής διανομής στην database');
			if (fail) fail.call(trapezi, conn);
			return;
		}

		trapezi.trapeziNeaDianomi2(conn, new Dianomi({
			kodikos: res.insertId,
			dealer: dealer,
		}), success, fail);
	});

	return this;
};

Trapezi.prototype.trapeziNeaDianomi2 = function(conn, dianomi, success, fail) {
	var trapezi = this, dianomiKodikos, idos, data, query;

	dianomiKodikos = dianomi.dianomiKodikosGet();
	idos = 'ΔΙΑΝΟΜΗ';
	data = (new Trapoula()).trapoulaAnakatema().trapoulaXartosiaGet().xartosia2string();

	query = "INSERT INTO `energia` (`dianomi`, `pektis`, `idos`, `data`) VALUES (" +
		dianomiKodikos + ", " + dianomi.dianomiDealerGet() + ", " +
		idos.json() + ", " + data.json() + ")";
	conn.connection.query(query, function(err, res) {
		if (err || (res.affectedRows != 1)) {
			console.error('αποτυχία εισαγωγής ενέργειας διανομής στην database');
			if (fail) fail.call(trapezi, conn);
			return;
		}

		trapezi.trapeziNeaDianomi3(conn, dianomi, new Energia({
			kodikos: res.insertId,
			dianomi: dianomiKodikos,
			idos: idos,
			data: data,
		}), success);
	});

	return this;
};

Trapezi.prototype.trapeziNeaDianomi3 = function(conn, dianomi, energia, callback) {
	var kinisiDianomi, kinisiEnergia, trapeziKodikos = this.trapeziKodikosGet(),
		dianomiKodikos = dianomi.dianomiKodikosGet(), dealer = dianomi.dianomiDealerGet(),
		fila = energia.energiaDataGet();

	kinisiDianomi = new Kinisi({
		idos: 'DN',
		data: {
			kodikos: dianomiKodikos,
			trapezi: trapeziKodikos,
			dealer: dealer,
		},
	});

	kinisiEnergia = new Kinisi({
		idos: 'EG',
		data: {
			kodikos: energia.energiaKodikosGet(),
			trapezi: trapeziKodikos,
			dianomi: dianomiKodikos,
			pektis: dealer,
			idos: energia.energiaIdosGet(),
			data: energia.energiaDataGet(),
		},
	});

	callback.call(this, conn, kinisiDianomi, kinisiEnergia);
	return this;
};

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Η μέθοδος "trapeziFilaSaveSet" κρατά τα φύλλα της τρέχουσας διανομής στη
// λίστα "filaSave" δεικοτοδοτημένα με τη θέση του παίκτη. Αν δεν καθοριστεί
// θέση καλείται αναδρομικά για όλες τις θέσεις. Τα φύλλα κρατούνται όχι ως
// χαρτωσιές, αλλά ως strings διότι αλλιώς κρατούνται by reference και στην
// πορεία αλλάζουν.

Trapezi.prototype.trapeziFilaSaveSet = function(thesi) {
	var trapezi = this, fila;

	if (thesi === undefined) {
		this.filaSave = {};
		this.trapeziThesiWalk(function(thesi) {
			trapezi.trapeziFilaSaveSet(thesi);
		});
		return this;
	}

	fila = this.partidaFilaGet(thesi);
	if (fila) this.filaSave[thesi] = fila.xartosia2string();

	return this;
};

// Η μέθοδος "trapeziFilaPrevSet" αντιγράφει τα κρατημένα φύλλα της διανομής
// από τη λίστα "filaSave" στη λίστα "filaPrev". Αν δεν καθοριστεί θέση καλείται
// αναδρομικά για όλες τις θέσεις.

Trapezi.prototype.trapeziFilaPrevSet = function(thesi) {
	var trapezi = this, fila;

	if (thesi === undefined) {
		this.filaPrev = {};
		this.trapeziThesiWalk(function(thesi) {
			trapezi.trapeziFilaPrevSet(thesi);
		});
		return this;
	}

	if (!this.hasOwnProperty('filaSave')) return this;
	fila = this.filaSave[thesi];
	if (fila) this.filaPrev[thesi] = fila;

	return this;
};

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Trapezi.projection =
	'`kodikos`, ' +
	'UNIX_TIMESTAMP(`stisimo`) AS `stisimo`, ' +
	'`pektis1`, `apodoxi1`, ' +
	'`pektis2`, `apodoxi2`, ' +
	'`pektis3`, `apodoxi3`, ' +
	'UNIX_TIMESTAMP(`poll`) AS `poll`';

Trparam.projection =
	'`param`, ' +
	'`timi`';

Dianomi.projection =
	'`kodikos`, ' +
	'`trapezi`, ' +
	'UNIX_TIMESTAMP(`enarxi`) AS `enarxi`, ' +
	'`dealer`, ' +
	'`kasa1`, `metrita1`, ' +
	'`kasa2`, `metrita2`, ' +
	'`kasa3`, `metrita3`, ' +
	'UNIX_TIMESTAMP(`telos`) AS `telos`';

Energia.projection =
	'`kodikos`, ' +
	'`dianomi`, ' +
	'`pektis`, ' +
	'`idos`, ' +
	'`data`, ' +
	'UNIX_TIMESTAMP(`pote`) AS `pote`';

Sizitisi.projection =
	'`kodikos`, ' +
	'`trapezi`, ' +
	'`pektis`, ' +
	'`sxolio`, ' +
	'UNIX_TIMESTAMP(`pote`) AS `pote`';

Sinedria.projection =
	'`pektis`, ' +
	'`klidi`, ' +
	'`ip`, ' +
	'UNIX_TIMESTAMP(`isodos`) AS `isodos`, ' +
	'`trapezi`, `thesi`, `simetoxi`';

Pektis.projection =
	'`login`, ' +
	'UNIX_TIMESTAMP(`egrafi`) AS `egrafi`, ' +
	'`onoma`, ' +
	'`email`, ' +
	'UNIX_TIMESTAMP(`poll`) AS `poll`';

Peparam.projection =
	'`param`, ' +
	'`timi`';

Sxesi.projection =
	'`sxetizomenos`, ' +
	'`sxesi`';

Prosklisi.projection =
	'`kodikos`, ' +
	'`trapezi`, ' +
	'`apo`, ' +
	'`pros`, ' +
	'UNIX_TIMESTAMP(`epidosi`) AS `epidosi`';

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
